package com.ruoyi.teacher.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiAttendanceListRequest;
import com.dingtalk.api.request.OapiAttendanceScheduleListbyusersRequest;
import com.dingtalk.api.response.OapiAttendanceListResponse;
import com.dingtalk.api.response.OapiAttendanceScheduleListbyusersResponse;
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.utils.JwtUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.dingtalk.pojo.dto.GroupDto;
import com.ruoyi.common.dingtalk.template.DingtalkTemplate;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.common.weChatRobot.utils.WechatRobotUtil;
import com.ruoyi.teacher.domain.Teacher;
import com.ruoyi.teacher.domain.TeacherWorkSchedule;
import com.ruoyi.teacher.mapper.TeacherMapper;
import com.ruoyi.teacher.mapper.TeacherWorkScheduleMapper;
import com.ruoyi.teacher.service.ITeacherWorkScheduleService;
import com.ruoyi.teaching.api.RemoteTeachingService;
import com.ruoyi.teaching.api.domain.CurriculumDto;
import com.taobao.api.ApiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 老师排班Service业务层处理
 *
 * @author clid
 * @date 2024-03-25
 */
@Service
public class TeacherWorkScheduleServiceImpl implements ITeacherWorkScheduleService {
    @Autowired
    private TeacherWorkScheduleMapper teacherWorkScheduleMapper;
    @Autowired
    private DingtalkTemplate dingtalkTemplate;
    @Autowired
    private RemoteTeachingService remoteTeachingService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private TeacherMapper teacherMapper;
    @Autowired
    private HttpServletRequest request;

    /**
     * 查询老师排班
     *
     * @param id 老师排班主键
     * @return 老师排班
     */
    @Override
    public TeacherWorkSchedule selectTeacherWorkScheduleById(Long id) {
        return teacherWorkScheduleMapper.selectTeacherWorkScheduleById(id);
    }

    /**
     * 批处理调度
     */
    @Override
    public void batchScheduling(Map<String, String> map) throws ApiException {
        String userId = new ArrayList<>( map.values()).get(0);
        Teacher teacher = teacherMapper.findbyLoginId(userId);
        String opUserId = teacher.getOpUserId();
        for (String date : map.keySet()) {
             TeacherWorkSchedule teacherWorkSchedule = new TeacherWorkSchedule();
            teacherWorkSchedule.setOpUserId(opUserId);
            teacherWorkSchedule.setTeacherName(teacher.getName());
            //暂时写死
            teacherWorkSchedule.setGroupId(1192355760L);
            teacherWorkSchedule.setGroupName("java考勤一组");
            teacherWorkSchedule.setClassId(1190605810L);
            teacherWorkSchedule.setClassName("java考勤一班");
            teacherWorkSchedule.setWorkDate(DateUtil.parseDate(date));
            teacherWorkSchedule.setCampusId(Long.valueOf(teacher.getCampusId()));
            teacherWorkSchedule.setSubjectId(Long.valueOf(teacher.getSubjectId()));
            Long groupId = teacherWorkSchedule.getGroupId();
            Date workDate = teacherWorkSchedule.getWorkDate();
            ArrayList<String> userIds = new ArrayList<>();
            userIds.add(opUserId);

            //将当前老师加入考勤组
            dingtalkTemplate.attendancePersonnelAdded(userIds, groupId);
            //调用钉钉排班
            dingtalkTemplate.groupSchedule(
                    groupId,
                    teacherWorkSchedule.getClassId(),
                    workDate.getTime(),
                    userIds
            );
            //先删除老数据
            teacherWorkScheduleMapper.deleteTeacherWorkSchedule(teacherWorkSchedule, userIds);
            teacherWorkScheduleMapper.insertTeacherWorkSchedule(teacherWorkSchedule);
        }
    }


    /**
     * 查询老师排班列表
     *
     * @param teacherWorkSchedule 老师排班
     * @return 老师排班
     */
    @Override
    public List<TeacherWorkSchedule> selectTeacherWorkScheduleList(TeacherWorkSchedule teacherWorkSchedule) {
        Date workDate = teacherWorkSchedule.getWorkDate();
        if (workDate == null) {
            workDate = DateUtil.date();
        }
        String userId = request.getHeader(SecurityConstants.DETAILS_USER_ID);
        Teacher teacher = teacherMapper.findbyLoginId(userId);
        String opUserId = teacher.getOpUserId();
        teacherWorkSchedule.setOpUserId(opUserId);
        List<TeacherWorkSchedule> teacherWorkSchedules = teacherWorkScheduleMapper.findByOpUserId(teacherWorkSchedule);
        return teacherWorkSchedules;
        //以下为批量操作
       /*

        curriculumDto.setCourseDate(workDate);
        //feign调用课程服务，拿到所有的课程表
        AjaxResult ajaxResult = remoteTeachingService.getList(curriculumDto);
        //拿到数据库的老师排班
        List<TeacherWorkSchedule> teacherWorkSchedules = teacherWorkScheduleMapper.selectTeacherWorkScheduleList(teacherWorkSchedule);
        //key-opuerid,value-排班
        Map<String, TeacherWorkSchedule> scheduleObjMap = teacherWorkSchedules.stream()
                .collect(Collectors.toMap(t -> {
                    return t.getOpUserId() + "-" + DateUtil.format(t.getWorkDate(), "yyyy-MM-dd");
                }, t -> t));
        JSONArray jsonArray = JSONUtil.parseArray(JSONUtil.toJsonStr(ajaxResult.get("data")));
        //userids
        List<String> stringArrayList = jsonArray.stream().map(o -> {
            return JSONUtil.parseObj(o).getStr("id");
        }).collect(Collectors.toList());
        //拿到所有有关的老师
        List<Teacher> teachers = teacherWorkScheduleMapper.getTeacherByUserIds(stringArrayList);
        Map<Long, String> teacherMap = teachers.stream().filter(teacher -> teacher.getOpUserId() != null)
                .collect(Collectors.toMap(Teacher::getId, Teacher::getOpUserId));
        ArrayList<CurriculumDto> arrayList = new ArrayList<>();
        List<TeacherWorkSchedule> scheduleList = jsonArray.stream().filter(obj -> {
            CurriculumDto bean = BeanUtil.toBean(obj, CurriculumDto.class);
            if (bean.getTeacherId() == null) {
                return false;
            }
            //是否已经排班
            if (CollUtil.isNotEmpty(teacherWorkSchedules)) {
                String opUserId = teacherMap.get(bean.getTeacherId());
                if (opUserId != null) {
                    Date courseDate = bean.getCourseDate();
                    TeacherWorkSchedule teacherWorkSchedule1 = scheduleObjMap.get(opUserId + "-" + DateUtil.format(courseDate, "yyyy-MM-dd"));
                    if (teacherWorkSchedule1 != null) {
                        scheduleObjMap.remove(opUserId + "-" + DateUtil.format(courseDate, "yyyy-MM-dd"));
                        return true;
                    }
                }
            }
            return true;
        }).map(o -> {
            CurriculumDto bean = BeanUtil.toBean(o, CurriculumDto.class);
            arrayList.add(bean);
            TeacherWorkSchedule teacherWorkSchedule1 = new TeacherWorkSchedule();
            BeanUtil.copyProperties(bean, teacherWorkSchedule1);
            teacherWorkSchedule1.setWorkDate(bean.getCourseDate());
            teacherWorkSchedule1.setOpUserId(teacherMap.get(bean.getTeacherId()));
            return teacherWorkSchedule1;
        }).collect(Collectors.toList());
        scheduleList.addAll(scheduleObjMap.values());
        //将课程老师存入redis，日期为key，value是老师的id
        Map<String, Set<String>> map = new HashMap<>();
        for (TeacherWorkSchedule obj : scheduleList) {
            String dateStr = DateUtil.format(obj.getWorkDate(), "yyyy-MM-dd");
            if (!map.containsKey(dateStr)) {
                Set<String> set = new HashSet<>();
                set.add(obj.getOpUserId());
                map.put(dateStr, set);
            } else {
                map.get(dateStr).add(obj.getOpUserId());
            }
        }
        redisService.setCacheObject("TEACHER-SCHEDULE-DATE-IDS", JSONUtil.toJsonStr(map));*/

    }

    /**
     * 新增老师排班
     *
     * @param teacherWorkSchedule 老师排班
     * @return 结果
     */
    @Override
    @Transactional
    public int insertTeacherWorkSchedule(TeacherWorkSchedule teacherWorkSchedule) throws ApiException {
        String userId = request.getHeader(SecurityConstants.DETAILS_USER_ID);
        Teacher teacher = teacherMapper.findbyLoginId(userId);
        String opUserId = teacher.getOpUserId();
        Long groupId = teacherWorkSchedule.getGroupId();
        Date workDate = teacherWorkSchedule.getWorkDate();
        teacherWorkSchedule.setSubjectId(Long.valueOf(teacher.getSubjectId()));
        teacherWorkSchedule.setCampusId(Long.valueOf(teacher.getCampusId()));
        ArrayList<String> userIds = new ArrayList<>();
        userIds.add(opUserId);
       /* //从redis中获取课程老师
        JSONObject jsonObject = JSONUtil.parseObj(redisService.getCacheObject("TEACHER-SCHEDULE-DATE-IDS"));
        String format = DateUtil.format(workDate, "yyyy-MM-dd");
        JSONArray jsonArray = JSONUtil.parseArray(JSONUtil.toJsonStr(jsonObject.get(format)));
        List<String> userIds = jsonArray.toList(String.class);
        //拿到所有老师
        List<Teacher> teachers = teacherWorkScheduleMapper.getTeacherByOpUserIds(userIds);*/

        //将当前老师加入考勤组
        dingtalkTemplate.attendancePersonnelAdded(userIds, groupId);
        //调用钉钉排班
        dingtalkTemplate.groupSchedule(
                groupId,
                teacherWorkSchedule.getClassId(),
                workDate.getTime(),
                userIds
        );
        //先删除老数据
        teacherWorkScheduleMapper.deleteTeacherWorkSchedule(teacherWorkSchedule, userIds);
        teacherWorkSchedule.setTeacherName(teacher.getName());
        teacherWorkSchedule.setOpUserId(opUserId);
        teacherWorkScheduleMapper.insertTeacherWorkSchedule(teacherWorkSchedule);
     /*   List<TeacherWorkSchedule> list = teachers.stream().map(t -> {
            TeacherWorkSchedule teacherRelationDto = new TeacherWorkSchedule();
            BeanUtil.copyProperties(teacherWorkSchedule, teacherRelationDto);
            teacherRelationDto.setTeacherName(t.getName());
            teacherRelationDto.setOpUserId(t.getOpUserId());
            return teacherRelationDto;
        }).collect(Collectors.toList());
        teacherWorkScheduleMapper.batchInsertTeacherWorkSchedule(list);*/
        return 1;
    }

    /**
     * 修改老师排班
     *
     * @param teacherWorkSchedule 老师排班
     * @return 结果
     */
    @Override
    public int updateTeacherWorkSchedule(TeacherWorkSchedule teacherWorkSchedule) {
        return teacherWorkScheduleMapper.updateTeacherWorkSchedule(teacherWorkSchedule);
    }


    /**
     * 删除老师排班信息
     *
     * @param id 老师排班主键
     * @return 结果
     */
    @Override
    public int deleteTeacherWorkScheduleById(Long id) {
        return teacherWorkScheduleMapper.deleteTeacherWorkScheduleById(id);
    }

    @Override
    public List<GroupDto> loadAttendanceSchedule() throws ApiException {
        return dingtalkTemplate.loadAttendanceSchedule();
    }

    /**
     * 钉钉考勤同步
     */
    @Override
    public void attendanceSynchronization() throws ApiException {
        //查询所有的人员
        List<Teacher> teachers = teacherMapper.selectTeacherList(new Teacher()).stream()
                .filter(t -> t.getOpUserId() != null).collect(Collectors.toList());
        List<String> userIds = teachers.stream().map(Teacher::getOpUserId).collect(Collectors.toList());
        //获取到所有的opuerids
        String userIdStr = userIds.stream().collect(Collectors.joining(","));
        String accessToken = dingtalkTemplate.getAccessToken();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/attendance/schedule/listbyusers");
        OapiAttendanceScheduleListbyusersRequest req = new OapiAttendanceScheduleListbyusersRequest();
        req.setOpUserId("3239173043-1814996873");
        req.setUserids(userIdStr);
        //开始时间，结束时间
        req.setFromDateTime(DateUtil.date().getTime());
        req.setToDateTime(DateUtil.offsetWeek(DateUtil.date(), 1).getTime());
        //获取到钉钉最新的考勤信息
        OapiAttendanceScheduleListbyusersResponse rsp = client.execute(req, accessToken);
        if (!JSONUtil.parseObj(rsp.getBody()).getStr("errmsg").equals("ok")) {
            return;
        }
        JSONArray jsonArray = JSONUtil.parseObj(rsp.getBody()).getJSONArray("result");
        if (jsonArray == null) {
            return;
        }
        List<JSONObject> list = jsonArray.toList(JSONObject.class);
        HashMap<String, String> map = new HashMap<>();
        HashMap<String, JSONObject> userSettingMap = new HashMap<>();
        for (JSONObject entries : list) {
            String key = entries.getStr("userid") + "-" + entries.getStr("work_date").replace("00:00:00", "").trim();
            map.put(key, entries.getStr("group_id") + "-" + entries.getStr("shift_id"));
            userSettingMap.put(key, entries);
        }
        TeacherWorkSchedule teacherWorkSchedule = new TeacherWorkSchedule();
        teacherWorkSchedule.setWorkDate(DateUtil.date());
        List<TeacherWorkSchedule> teacherWorkSchedules = teacherWorkScheduleMapper.selectTeacherWorkScheduleList(teacherWorkSchedule);

        //如果不为空，说明数据库中有记录
        if (CollUtil.isNotEmpty(teacherWorkSchedules)) {
            //过滤掉，剩下的都是不一致的
            List<Long> ids = teacherWorkSchedules.stream().filter(t -> {
                String opUserId = t.getOpUserId();
                String groupAndShiftStr = t.getGroupId() + "-" + t.getClassId();
                //过滤掉相同的
                String key = opUserId + "-" + DateUtil.format(t.getWorkDate(), "yyyy-MM-dd");
                //如果不存在，说明本地库中的数据不一致，就删掉
                if (!map.containsKey(key)) {
                    return true;
                }
                boolean tag = map.get(key).equals(groupAndShiftStr);
                if (tag) {
                    map.remove(key);
                }
                return !tag;
            }).map(TeacherWorkSchedule::getId).collect(Collectors.toList());
            //将不一致的删除
            if (CollUtil.isNotEmpty(ids)) {
                teacherWorkScheduleMapper.deleteTeacherWorkScheduleByIds(ids);
            }

        }
        //查看map中是否还有，有就添加
        if (CollUtil.isNotEmpty(map)) {
            //获取所有的考勤组和考勤班次
            HashMap<Long, String> classMap = new HashMap<>();
            List<GroupDto> groupDtos = dingtalkTemplate.loadAttendanceSchedule();
            Map<Long, String> groupMap = groupDtos.stream().map(g -> {
                g.getClassList().forEach(cm -> {
                    classMap.put(cm.getClassId(), cm.getClassName());
                });
                return g;
            }).collect(Collectors.toMap(GroupDto::getGroupId, GroupDto::getGroupName));

            //获取相关的老师信息
            Map<String, Teacher> teacherMap = teachers.stream().collect(Collectors.toMap(s -> s.getOpUserId(), s -> s));
            Set<String> differentSetting = map.keySet();
            List<TeacherWorkSchedule> scheduleList = differentSetting.stream().map(d -> {
                JSONObject jsonObject = userSettingMap.get(d);
                TeacherWorkSchedule tws = new TeacherWorkSchedule();
                String opUserId = jsonObject.getStr("userid");
                tws.setOpUserId(opUserId);
                tws.setWorkDate(DateUtil.parse(jsonObject.getStr("work_date")));
                Long groupId = jsonObject.getLong("group_id");
                Long shiftId = jsonObject.getLong("shift_id");
                tws.setGroupId(groupId);
                tws.setClassId(shiftId);
                tws.setGroupName(groupMap.get(groupId));
                tws.setClassName(classMap.get(shiftId));
                Teacher teacher = teacherMap.get(opUserId);
                tws.setCampusId(Long.valueOf(teacher.getCampusId()));
                tws.setSubjectId(Long.valueOf(teacher.getSubjectId()));
                tws.setTeacherName(teacher.getName());
                return tws;
            }).collect(Collectors.toList());
            teacherWorkScheduleMapper.batchInsertTeacherWorkSchedule(scheduleList);
        }


    }

    /**
     * 打卡提醒
     */
    @Override
    public void punchReminder() throws ApiException {
        //获取今日需要打卡的用户
        TeacherWorkSchedule teacherWorkSchedule = new TeacherWorkSchedule();
        teacherWorkSchedule.setWorkDate(DateUtil.date());
        List<TeacherWorkSchedule> teacherWorkSchedules = teacherWorkScheduleMapper.selectTodayTeacherWorkScheduleList(teacherWorkSchedule);
        if (CollUtil.isEmpty(teacherWorkSchedules)) {
            return;
        }
        List<String> opUserIds = teacherWorkSchedules.stream().map(TeacherWorkSchedule::getOpUserId).collect(Collectors.toList());
        Map<String, String> opUserIdsMap = opUserIds.stream().collect(Collectors.toMap(t -> t, t -> t));
        String accessToken = dingtalkTemplate.getAccessToken();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/attendance/list");
        OapiAttendanceListRequest req = new OapiAttendanceListRequest();
        req.setWorkDateFrom("2024-3-26 09:00:00");
        req.setWorkDateTo("2024-3-26 18:00:00");
        req.setUserIdList(opUserIds);
        req.setOffset(0L);
        req.setLimit(50L);
        req.setIsI18n(false);
        OapiAttendanceListResponse rsp = client.execute(req, accessToken);
        if (!("ok".equals(JSONUtil.parseObj(rsp.getBody()).getStr("errmsg")))) {
            return;
        }
        JSONArray recordresult = JSONUtil.parseObj(rsp.getBody()).getJSONArray("recordresult");
        if (recordresult == null || recordresult.isEmpty()) {
            //都没有打卡，根据上班还是下班进行通知
            //通知打卡
            reminderOfCheck(opUserIdsMap);
            return;
        }
        //获取打卡结果
        recordresult.stream().filter(re -> {
            JSONObject jsonObject = JSONUtil.parseObj(re);
            return jsonObject.get("locationResult").equals("Normal");
        }).forEach(r -> {
            JSONObject jsonObject = JSONUtil.parseObj(r);
            opUserIdsMap.remove(jsonObject.getStr("userId"));
        });
        //都已经打卡
        if (CollUtil.isEmpty(opUserIdsMap)) {
            return;
        }
        //通知打卡
        reminderOfCheck(opUserIdsMap);
    }


    /**
     * 检查打卡
     *
     * @param opUserIdsMap Op用户id映射
     */
    private void reminderOfCheck(Map<String, String> opUserIdsMap) {
        //查询未打卡的手机号
        ArrayList<String> notSignedOpUserIds = new ArrayList<>(opUserIdsMap.values());
        List<Teacher> teachers = teacherMapper.selectTeacherByUserIds(notSignedOpUserIds);
        List<String> phones = teachers.stream().filter(t -> t.getPhone() != null).map(Teacher::getPhone).collect(Collectors.toList());
        WechatRobotUtil.sendTextMessage("可爱的元宝提醒你，今日您还没有打卡哦", phones);
    }
}
